#-*- coding: utf8 -*-

import os
import shutil
import time
import datetime
import json
import uuid
import urllib
import base64
import math
import hashlib
import psycopg2
import pytz
import pandas as pd
import xlwt
import zipfile
import threading

from bottle import route, run, redirect, request, default_app
from bottle import static_file, view
from beaker.middleware import SessionMiddleware
from configparser import ConfigParser
from apscheduler.schedulers.background import BackgroundScheduler
from xpinyin import Pinyin


@route('/downloads/<filename:re:.*\.*>')
def static_css(filename):
    return static_file(filename, root='.' + config['server']['download_path'])


@route('/favicon.ico')
def static_favicon():
    return static_file('favicon.ico', root='./')


@route('/css/<filename:re:.*\.*>')
def static_css(filename):
    return static_file(filename, root='./static/css')


@route('/fonts/<filename:re:.*\.*>')
def static_font(filename):
    return static_file(filename, root='./static/fonts')


@route('/images/<filename:re:.*\.*>')
def static_image(filename):
    return static_file(filename, root='./static/images')


@route('/js/<filename:re:.*\.*>')
def static_js(filename):
    return static_file(filename, root='./static/js')


@route('/file/<filename:re:.*\.*>')
def static_media_file(filename):
    path = config['backup']['path']
    ext = os.path.splitext(filename)[-1].lower()
    exts = ['.jpg', '.jpeg', '.png', '.gif']
    if ext in exts:
        return static_file(filename, root=path)
    else:
        return static_file(filename, root=path, download=True)


@route('/')
@view('index')
def index():
    check_login()
    session = request.environ.get('beaker.session')
    current_user = session.get('current_user', None)
    return {
        'user_name': current_user['en_name'] or current_user['name'],
        'users': get_users(),
        'today': time.strftime('%Y-%m-%d', time.localtime(time.time())),
        'timezones': pytz.common_timezones
    }


@route('/logout')
def logout():
    if config['server']['use_sso'] == 1:
        session = request.environ.get('beaker.session')
        session['current_user'] = None
        session.save()
        url = config['server']['sso_logout_uri']
        return {
            'redirect_url': url
        }
    else:
        return {
            'redirect_url': '/bye'
        }


@route('/bye')
def bye():
    return 'bye'


@route('/oauth2/callback')
def callback():
    session = request.environ.get('beaker.session')
    state = session.get('state', '')
    current_state = request.GET.get('state', '')
    #if (current_state != state):
    #    return 'Invalid state'
    code = request.GET.get('code', '')
    access_token = get_access_token(code)
    get_user_info(access_token)
    return redirect('/')


@route('/api/ping')
def ping():
    result = {
        'code': 200,
        'message': '',
        'data': None
    }
    result['data'] = 'pong'
    return result


@route('/api/get_list')
def get_list():
    result = {
        'page_number': 1,
        'page_count': 1,
        'total': 0,
        'list': None
    }
    if not is_login():
        return result

    id = request.GET.get('id', '');
    start_date = request.GET.get('start_date', '')
    end_date = request.GET.get('end_date', '')
    timezone = request.GET.get('timezone', 'Asia/Shanghai')
    from_user = request.GET.get('from_user', '')
    users = request.GET.get('users', '')
    room = request.GET.get('room', '')
    sort = request.GET.get('sort', 'asc')
    page_size = int(request.GET.get('page_size', '50'))
    page_number = int(request.GET.get('page_number', '1'))
    return get_messages(id, start_date, end_date, timezone, from_user,
                        users, room, sort, page_size, page_number)


@route('/api/get_download_url')
def get_download_url():
    result = {
        'url': '',
        'error': 1
    }
    if not is_login():
        return result

    start_date = request.GET.get('start_date', '')
    end_date = request.GET.get('end_date', '')
    timezone = request.GET.get('timezone', 'Asia/Shanghai')
    from_user = request.GET.get('from_user', '')
    sort = request.GET.get('sort', 'asc')
    result['url'] = get_zip_file(start_date, end_date, timezone,
                                 from_user, sort)
    result['error'] = 0
    return result


def get_users():
    users = []
    user_ids = []
    conn = get_connection()
    cursor = conn.cursor()
    try:
        sql = 'select distinct from_user from messages ' +\
                'where length(from_user) != 32 order by from_user'
        cursor.execute(sql)
        rs = cursor.fetchall()
        for index in range(len(rs)):
            user_ids.append(rs[index][0])
        user_names = convert_user_ids(','.join(user_ids)).split(',')
        pinyin = Pinyin()
        for index in range(len(user_ids)):
            users.append({
                'user_id': user_ids[index],
                'name': user_names[index],
                'pinyin': pinyin.get_pinyin(user_names[index])
            })
        users = sorted(users, key=lambda i:i['pinyin'])
    except:
        pass
    finally:
        cursor.close()
    conn.close()
    return users


def get_messages(id, start_date, end_date, timezone, from_user, users, room,
                 sort, page_size, page_number):
    return do_message_query(id, start_date, end_date, timezone, from_user,
                            users, room, sort, page_size, page_number)


def get_zip_file(start_date, end_date, timezone, from_user, sort):
    start_date = start_date.strip()
    end_date = end_date.strip()
    timezone = timezone.strip()
    from_user = from_user.strip()
    sort = sort.strip()
    res = do_message_query('', start_date, end_date, timezone, from_user,
                           '', '', sort)
    records = res['list']
    count = len(records)
    flags = (start_date, end_date, timezone, from_user, sort, str(count))
    m = hashlib.md5()
    m.update(('|'.join(flags)).encode('utf-8'))

    filename = m.hexdigest()
    download_path = config['server']['download_path']
    path = config['server']['full_download_path']
    zip_file = download_path + filename + '.zip'
    full_zip_file = config['backup']['root_path'] + zip_file
    if os.path.exists(full_zip_file):
        return zip_file

    path = path + filename + '/'
    file_path = path + 'files/'
    if not os.path.exists(path):
        os.makedirs(path)
    if not os.path.exists(file_path):
        os.makedirs(file_path)
    for record in records:
        file = record['file_path']
        if len(file) > 0:
            source_path = config['backup']['path'] + file
            target_path = file_path + file[13:]
            if os.path.exists(source_path):
                shutil.copyfile(source_path, target_path)
                record['file_path'] = 'files/' + file[13:]
            else:
                record['file_path'] = ''
        if len(record['raw_data']) > 0:
            json_data = json.loads(record['raw_data'])
            raw_data = json.dumps(json_data, ensure_ascii=False)
            record['raw_data'] = raw_data
    columns = ['seq', 'action', 'from', 'to', 'room', 'time', 'type',
               'content', 'file', 'data']

    seq_list = []
    action_list = []
    from_list = []
    to_list = []
    room_list = []
    time_list = []
    type_list = []
    file_list = []
    data_list = []
    content_list = []
    for record in records:
        seq_list.append(record['sequance'])
        action_list.append(record['action'])
        from_list.append(record['from_user'])
        to_list.append(record['to_user_list'])
        room_list.append(record['room_id'])
        time_list.append(record['message_time'])
        type_list.append(record['message_type'])
        content_list.append(record['content'])
        file_list.append(record['file_path'])
        data_list.append(record['raw_data'])
    df = pd.DataFrame({
        'seq': pd.Series(seq_list),
        'action': pd.Series(action_list),
        'from': pd.Series(from_list),
        'to': pd.Series(to_list),
        'room': pd.Series(room_list),
        'time': pd.Series(time_list),
        'type': pd.Series(type_list),
        'content': pd.Series(content_list),
        'file': pd.Series(file_list),
        'data': pd.Series(data_list)
    })
    df.to_csv(path + 'records.csv', index=False, columns=columns,
              encoding='utf-8-sig')

    workbook = xlwt.Workbook(encoding='utf-8')
    sheet = workbook.add_sheet('records')
    bold_style = xlwt.easyxf('font: bold 1')
    hyperlink_style = xlwt.XFStyle()
    font = xlwt.Font()
    font.underline = xlwt.Font.UNDERLINE_SINGLE
    font.colour_index = 4
    hyperlink_style.font = font
    for i in range(len(columns)):
        sheet.write(0, i, columns[i], bold_style)
    index = 0
    for record in records:
        index += 1
        if index > 65535:
            break
        sheet.write(index, 0, record['sequance'])
        sheet.write(index, 1, record['action'])
        sheet.write(index, 2, record['from_user'])
        sheet.write(index, 3, record['to_user_list'])
        sheet.write(index, 4, record['room_id'])
        sheet.write(index, 5, record['message_time'])
        sheet.write(index, 6, record['message_type'])
        sheet.write(index, 7, record['content'])
        if len(record['file_path']) > 0:
            text = record['file_path']
            link = 'HYPERLINK("%s";"%s")' % ('./' + text, text)
            sheet.write(index, 8, xlwt.Formula(link), hyperlink_style)
        else:
            sheet.write(index, 8, '')
        sheet.write(index, 9, record['raw_data'])
    sheet.set_panes_frozen(True)
    sheet.set_horz_split_pos(1)
    sheet.set_remove_splits(True)
    widths = [12, 12, 36, 36, 36, 20, 12, 50, 50, 50]
    for i in range(len(widths)):
        sheet.col(i).width = widths[i] * 256
    workbook.save(path + 'records.xls')

    z = zipfile.ZipFile(full_zip_file, 'w', zipfile.ZIP_DEFLATED)
    for dirpath, dirnames, filenames in os.walk(path):
        fpath = dirpath.replace(path, '')
        fpath = fpath and fpath + os.sep or ''
        for filename in filenames:
            z.write(os.path.join(dirpath, filename), fpath + filename)
    z.close()
    shutil.rmtree(path, ignore_errors=True)
    return zip_file


def do_message_query(id, start_date, end_date, timezone, from_user, users,
                     room, sort, page_size=0, page_number=1):
    result = {
        'page_number': 1,
        'page_count': 1,
        'total': 0,
        'list': []
    }
    conn = get_connection()
    where = ''
    tz = pytz.timezone(timezone)
    id = id.strip().replace("'", '')
    start_date = start_date.strip().replace("'", '')
    end_date = end_date.strip().replace("'", '')
    from_user = from_user.strip().replace("'", '')
    users = users.strip().replace("'", '')
    room = room.strip().replace("'", '')
    page_size = int(page_size)
    page_number = int(page_number)

    condition = ''
    if start_date != '':
        start_date = convert_date(start_date + ' 00:00:00', tz) + '.000'
    if end_date != '':
        end_date = convert_date(end_date + ' 23:59:59', tz) + '.999'
    if start_date != '' and end_date != '':
        condition = "message_time >= '%s' and message_time <= '%s'"
        condition = condition % (start_date, end_date)
    elif start_date != '':
        condition = "message_time >= '%s'" % start_date
    elif end_date != '':
        condition = "message_time <= '%s'" % end_date
    if condition != '':
        where = where + (' and ' if where != '' else '') + '(' + condition + ')'
    if id != '':
        where = "id = '%s'" % id

    if from_user != '':
        condition = "from_user = '%s'" % from_user
        where = where + (' and ' if where != '' else '') + '(' + condition + ')'

    if users != '' :
        user_list = users.split(',')
        if len(user_list) == 2:
            condition = "(from_user = '%s' and to_user_list = '%s')"
            condition1 = condition % (user_list[0], user_list[1])
            condition2 = condition % (user_list[1], user_list[0])
            condition = '%s or %s' % (condition1, condition2)
            where = where + (' and ' if where != '' else '') +\
                    '(' + condition + ')'

    if room != '':
        condition = "room_id = '%s'" % room
        where = where + (' and ' if where != '' else '') + '(' + condition + ')'

    if where == '':
        where = '1 = 1'

    total = 0
    cursor = conn.cursor()
    try:
        sql = 'select count(id) from messages where ' + where
        cursor.execute(sql)
        rs = cursor.fetchall()
        if len(rs) > 0:
            total = int(rs[0][0])
    except:
        pass
    finally:
        cursor.close()
    if page_size > 0:
        page_count = max(math.ceil(total / page_size), 1)
        page_number = max(min(page_number, page_count), 1)
    else:
        page_count = 1
        page_number = 1

    messages = []
    cursor = conn.cursor()
    try:
        fields = 'id, sequance, action, from_user, to_user_list, room_id, '+\
                'message_time, message_type, content, raw_data, file_path, ' +\
                'relative_id'
        sql = 'select %s from messages where %s order by sequance %s'
        if page_size > 0:
            sql += ' limit %d offset %d'
            offset = (page_number - 1) * page_size
            sql = sql % (fields, where, sort, page_size, offset)
        else:
            sql = sql % (fields, where, sort)
        cursor.execute(sql)
        messages = cursor.fetchall()
    except:
        pass
    finally:
        cursor.close()
    for index in range(len(messages)):
        msg = messages[index]
        record = {}
        record['id'] = msg[0]
        record['sequance'] = msg[1]
        record['action'] = msg[2]
        record['raw_from_user'] = msg[3]
        record['raw_to_user_list'] = msg[4]
        record['from_user'] = convert_user_ids(msg[3])
        record['to_user_list'] = convert_user_ids(msg[4])
        record['room_id'] = msg[5]
        record['message_time'] = msg[6]
        record['message_type'] = msg[7]
        record['content'] = msg[8]
        record['raw_data'] = msg[9]
        record['file_path'] = msg[10]
        record['relative_id'] = msg[11]
        record['message_time'] = format_date(str(record['message_time'])[:19], tz)
        record['chat_record_files'] = get_chat_record_files(conn, msg[0])
        result['list'].append(record)

    result['page_number'] = page_number
    result['page_count'] = page_count
    result['total'] = total

    conn.close()
    return result


def get_chat_record_files(conn, message_id):
    files = []
    cursor = conn.cursor()
    try:
        sql = 'select file_path from chat_record_files ' +\
                'where message_id = %s order by sequance'
        cursor.execute(sql, [message_id])
        file_list = cursor.fetchall()
        for record in file_list:
            files.append(record[0])
    except:
        pass
    finally:
        cursor.close()
    return files


def check_login():
    session = request.environ.get('beaker.session')
    current_user = session.get('current_user', None)
    if not current_user:
        if config['server']['use_sso'] == 1:
            server = config['server']
            redirect_uri = server['host'] + '/oauth2/callback'
            state = str(uuid.uuid1())
            session['state'] = state
            session.save()
            url = server['sso_authorization_uri']
            params = {}
            params['response_type'] = 'code'
            params['scope'] = ''
            params['state'] = state
            params['client_id'] = server['sso_client_id']
            params['redirect_uri'] = redirect_uri
            url = url + '?' + urllib.parse.urlencode(params)
            return redirect(url)
        else:
            user = {'id': 'admin', 'name': 'Admin', 'en_name': 'Admin'}
            session = request.environ.get('beaker.session')
            session['current_user'] = user
            session.save()


def is_login():
    session = request.environ.get('beaker.session')
    current_user = session.get('current_user', None)
    if not current_user:
        return False
    return True


def get_access_token(code):
    server = config['server']
    redirect_uri = server['host'] + '/oauth2/callback'
    url = server['sso_token_uri']
    params = {}
    params['grant_type'] = 'authorization_code'
    params['scope'] = ''
    params['code'] = code
    params['client_id'] = server['sso_client_id']
    params['client_secret'] = server['sso_client_secret']
    params['redirect_uri'] = server['host'] + '/oauth2/callback'
    params = urllib.parse.urlencode(params).encode('utf8')
    req = urllib.request.Request(url, params)
    res = urllib.request.urlopen(req)
    data = res.read().decode('utf8')
    return json.loads(data)['access_token']


def get_user_info(access_token):
    server = config['server']
    url = server['user_info_uri']
    headers = {
        'Authorization': 'Bearer ' + access_token,
        'Accept': 'application/json'
    }
    req = urllib.request.Request(url=url, headers=headers)
    res = urllib.request.urlopen(req)
    data = res.read().decode('utf8')
    user = json.loads(data)['user']
    session = request.environ.get('beaker.session')
    session['current_user'] = user
    session.save()


def get_connection():
    db = config['database']
    conn = psycopg2.connect(
            host=db['host'],
            port=db['port'],
            database=db['database'],
            user=db['user'],
            password=db['password'])
    return conn


def convert_date(date_text, timezone):
    date_text = date_text[0:19]
    timestamp = int(time.mktime(time.strptime(date_text, '%Y-%m-%d %H:%M:%S')))
    offset = get_timezone_offset(timezone, timestamp)
    time_array = time.localtime(timestamp - (offset - 3600 * 8))
    return time.strftime('%Y-%m-%d %H:%M:%S', time_array)


def format_date(date_text, timezone):
    date_text = date_text[0:19]
    timestamp = int(time.mktime(time.strptime(date_text, '%Y-%m-%d %H:%M:%S')))
    offset = get_timezone_offset(timezone, timestamp)
    time_array = time.localtime(timestamp + offset - 3600 * 8)
    return time.strftime('%Y-%m-%d %H:%M:%S', time_array)


def get_timezone_offset(timezone, timestamp):
    date_time = datetime.datetime.utcfromtimestamp(timestamp)
    date_time = timezone.normalize(timezone.localize(date_time))
    offset = str(date_time)[19:]
    minus = offset[0] == '-'
    offset = offset[1:]
    offsets = offset.split(':')
    hours = int(offsets[0])
    minutes = int(offsets[1])
    return (hours * 3600 + minutes * 60) * (-1 if minus else 1)


def convert_user_ids(user_ids):
    names = []
    ids = user_ids.split(',')
    for id in ids:
        name = id
        if (id in weixin_users):
            name = weixin_users[id]['name'] or weixin_users[id]['english_name']
        names.append(name)
    return ','.join(names)


def fetch_weixin_users():
    sql = 'select user_id, name, english_name from weixin_users'
    users = do_query(sql)
    for user in users:
        weixin_users[user[0]] = {
            'name': user[1],
            'english_name': user[2]
        }


def save_weixin_users(users):
    for user in users:
        user_id = user['user_id']
        name = user['name']
        english_name = user['english_name']
        sql = 'select user_id from weixin_users where user_id = %s'
        user_list = do_query(sql, [user_id])
        params = []
        now = datetime.datetime.now()
        if len(user_list) == 0:
            sql = '''insert into weixin_users (user_id, name, english_name,
                    created_at, updated_at) values (%s, %s, %s, %s, %s)'''
            params = [user_id, name, english_name, now, now]
        else:
            sql = '''update weixin_users set name = %s, english_name = %s,
                    updated_at = %s where user_id = %s'''
            params = [name, english_name, now, user_id]
        do_execute(sql, params)


def save_deps(depts):
    sql = 'select id from departments'
    result = do_query(sql)
    dept_dict = {}
    for record in result:
        dept_dict[record[0]] = record
    insert_sql = '''insert into departments (id, name, parent_id, sort_order,
            created_at, updated_at) values (%s, %s, %s, %s, %s, %s)'''
    update_sql = '''update departments set id = %s, name = %s, parent_id = %s,
            sort_order = %s, updated_at = %s where id = %s'''
    delete_sql = 'delete from departments where id = %s'
    for dept in depts:
        now = datetime.datetime.now()
        params = [dept['id'], dept['name'], dept['parentid'], dept['order'],
                  now]
        if dept['id'] in dept_dict:
            params.append(dept['id'])
            do_execute(update_sql, params)
            del dept_dict[dept['id']]
        else:
            params.append(now)
            do_execute(insert_sql, params)
    for dept_id in dept_dict.keys():
        do_execute(delete_sql, [dept_id])


def save_employees(employees, depts):
    sql = 'select id from employees'
    result = do_query(sql)
    employee_dict = {}
    for record in result:
        employee_dict[record[0]] = record
    dept_dict = {}
    for dept in depts:
        dept_dict[dept['id']] = dept
    insert_sql = '''insert into employees (id, name, english_name, alias_name,
            gender, avatar, qr_code, position, mobile, telephone, email,
            enable, status, deleted, created_at, updated_at) values
            (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)'''
    update_sql = '''update employees set id = %s, name = %s,
            english_name = %s, alias_name = %s, gender = %s, avatar = %s,
            qr_code = %s, position = %s, mobile = %s, telephone = %s,
            email = %s, enable = %s, status = %s updated_at = %s
            where id = %s'''
    for record in employees:
        e = parse_employee(record, dept_dict)
        now = datetime.datetime.now()
        params = [e['id'], e['name'], e['english_name'], e['alias_name'],
                  e['gender'], e['avatar'], e['qr_code'], e['position'],
                  e['mobile'], e['telephone'], e['email'], e['enable'],
                  e['status'], e['deleted']]
        if e['id'] in employee_dict:
            params.append(now)
            params.append(e['id'])
            do_execute(update_sql, params)
            del employee_dict[e['id']]
        else:
            params.append(now)
            params.append(now)
            do_execute(insert_sql, params)
        save_employee_depts(e['id'], e['departments'])
    for employee_id in employee_dict.keys():
        sql = 'update employees set deleted = true where id = %s'
        do_execute(sql, [employee_id])
        save_employee_depts(employee_id, [])


def save_employee_depts(employee_id, depts):
    sql = 'select id from employee_departments where employee_id = %s'
    result = do_query(sql, [employee_id])
    old_count = len(result)
    count = len(depts)
    if old_count > count:
        delete_sql = 'delete from employee_departments where id = %s'
        for index in range(old_count - count):
            record = result.pop()
            do_execute(delete_sql, [record[0]])
    insert_sql = '''insert into employee_departments (
            employee_id, department_id, department_index, sequence,
            created_at, updated_at) values (%s, %s, %s, %s, %s, %s)'''
    update_sql = '''update employee_departments set employee_id = %s,
            department_id = %s, department_index = %s, sequence = %s,
            updated_at = %s where id = %s'''
    index = 0
    for dept in depts:
        now = datetime.datetime.now()
        params = [employee_id, dept['department_id'], dept['department_index'],
                  dept['sequence']]
        if index < old_count:
            params.append(now)
            params.append(result[index][0])
            do_execute(update_sql, params)
        else:
            params.append(now)
            params.append(now)
            do_execute(insert_sql, params)
        index = index + 1


def parse_employee(record, dept_dict):
    employee = {}
    employee['id'] = record['userid']
    employee['name'] = record['name']
    employee['english_name'] = record['english_name']
    employee['alias_name'] = record['alias']
    employee['gender'] = record['gender']
    employee['avatar'] = record['avatar']
    employee['qr_code'] = record['qr_code']
    employee['position'] = record['position']
    employee['mobile'] = record['mobile']
    employee['telephone'] = record['telephone']
    employee['email'] = record['email'].lower()
    employee['enable'] = record['enable']
    employee['status'] = record['status']
    employee['deleted'] = False
    employee['departments'] = []
    if record['department'] is not None:
        sequence = 0
        for dept_id in record['department']:
            sequence = sequence + 1
            dept_ids = [dept_id]
            while True:
                current_id = dept_ids[0]
                dept = dept_dict[current_id]
                if dept['parentid'] == 0:
                    break
                dept_ids.insert(0, dept['parentid'])
            department_index = 0
            for current_id in dept_ids:
                department_index = department_index + 1
                department = {}
                department['department_id'] = current_id
                department['department_index'] = department_index
                department['sequence'] = sequence
                employee['departments'].append(department)
    return employee


def get_all_wexin_users():
    users = []
    dept_ids = []
    depts = []
    employees = []
    params = {
        'access_token': get_weixin_access_token()
    }
    data = do_get('https://qyapi.weixin.qq.com/cgi-bin/department/list', params)
    if data['errcode'] == 0:
        for dept in data['department']:
            depts.append(dept)
            if dept['parentid'] == 0:
                dept_ids.append(dept['id'])
    for dept_id in dept_ids:
        params = {
            'access_token': get_weixin_access_token(),
            'department_id': dept_id,
            'fetch_child': 1
        }
        data = do_get('https://qyapi.weixin.qq.com/cgi-bin/user/list', params)
        if data['errcode'] == 0:
            for user in data['userlist']:
                users.append({
                    'user_id': user['userid'],
                    'name': user['name'],
                    'english_name': user['english_name']
                })
                employees.append(user)
    save_weixin_users(users)
    save_deps(depts)
    save_employees(employees, depts)
    fetch_weixin_users()


def get_weixin_access_token():
    now = int(time.time())
    if len(weixin_token['access_token']) > 0 and\
            weixin_token['create_time'] + weixin_token['expires_in'] - 5 > now:
        return weixin_token['access_token']

    params = {
        'corpid': config['weixin']['corpid'],
        'corpsecret': config['weixin']['app_secret']
    }
    data = do_get('https://qyapi.weixin.qq.com/cgi-bin/gettoken', params)
    if data['errcode'] == 0:
        weixin_token['access_token'] = data['access_token']
        weixin_token['expires_in'] = data['expires_in']
    else:
        weixin_token['access_token'] = ''
    weixin_token['create_time'] = int(time.time())
    return weixin_token['access_token']


def do_get(url, params=None):
    if params is None:
        req = urllib.request.Request(url)
    else:
        params = urllib.parse.urlencode(params)
        url = url + '?' + params
        req = urllib.request.Request(url)
    res = urllib.request.urlopen(req)
    data = res.read().decode('utf8')
    data = json.loads(data)
    return data


def do_post(url, params):
    headers = {}
    headers['Content-Type'] = 'application/json; charset=utf-8'
    params = json.dumps(params).encode('utf8')
    req = urllib.request.Request(url, params, headers)
    res = urllib.request.urlopen(req)
    data = res.read().decode('utf8')
    data = json.loads(data)
    return data


def do_query(sql, params=None, fields=None):
    result = []
    conn = get_connection()
    cursor = conn.cursor()
    try:
        cursor.execute(sql, params)
        result = cursor.fetchall()
        if fields is not None:
            if isinstance(fields, str):
                fields = fields.split(',')
            records = []
            for index in range(len(result)):
                item = result[index]
                record = {}
                for field_index in range(min(len(item), len(fields))):
                    value = item[field_index]
                    record[fields[field_index].strip()] = value
                    records.append(record)
            result = records
    except:
        pass
    finally:
        cursor.close()
    conn.close()
    return result


def do_execute(sql, params=None):
    result = 0
    conn = get_connection()
    cursor = conn.cursor()
    try:
        cursor.execute(sql, params)
        result = cursor.rowcount
        try:
            conn.commit()
        except:
            result = 0
    except:
        result = 0
    finally:
        cursor.close()
    conn.close()
    return result


def read_config():
    path = os.getcwd()
    if not path.endswith('/'):
        path = path + '/'
    config_file = path + 'config.cfg'
    cp = ConfigParser()
    cp.read(config_file)
    config = {}
    for section in cp.sections():
        config[section] = {}
        for item in cp.items(section):
            config[section][item[0]] = item[1]
    backup_path = config['backup']['path']
    if not backup_path.startswith('/'):
        backup_path = path + backup_path
    if not backup_path.endswith('/'):
        backup_path = backup_path + '/'
    session_path = config['server']['session_path']
    if not session_path.startswith('/'):
        session_path = path + session_path
    full_download_path = config['server']['download_path']
    if not full_download_path.startswith('/'):
        full_download_path = path + full_download_path
    if not full_download_path.endswith('/'):
        full_download_path = full_download_path + '/'
    download_path = full_download_path[(len(path) - 1):]
    config['backup']['root_path'] = path
    config['backup']['path'] = backup_path
    config['database']['port'] = int(config['database']['port'])
    config['server']['port'] = int(config['server']['port'])
    config['server']['session_expires'] =\
            int(config['server']['session_expires'])
    config['server']['session_path'] = session_path
    config['server']['download_path'] = download_path
    config['server']['full_download_path'] = full_download_path
    if config['server']['port'] != 80:
        config['server']['host'] = config['server']['host'] + ':' +\
                str(config['server']['port'])
    config['server']['use_sso'] = int(config['server']['use_sso'])
    return config


def run_server():
    global config
    global weixin_users
    global weixin_token
    config = read_config()
    weixin_users = {}
    weixin_token = {
        'access_token': '',
        'expires_in': 7200,
        'create_time': int(time.time())
    }
    fetch_weixin_users()
    threading.Thread(target=get_all_wexin_users, args=()).start()
    scheduler = BackgroundScheduler()
    scheduler.add_job(get_all_wexin_users, 'cron', hour=23, minute=30)
    scheduler.start()
    session_opts = {
        'session.type': 'file',
        'session.cookie_expires': config['server']['session_expires'],
        'session.data_dir': config['server']['session_path'],
        'session.auto': True
    }
    app = default_app()
    app = SessionMiddleware(app, session_opts)
    run(app=app, host='0.0.0.0', port=config['server']['port'],
        server='tornado', reloader=False)


if __name__ == '__main__':
    run_server()
